package com.apes.framework.es;

import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.jpa.spec.model.Filter;
import com.apes.framework.jpa.spec.model.Group;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;

import java.util.Map;

public class EsDsl {

    public static QueryBuilder build(SimpleRequest request, Map<String, String> mapping) {
        Group group = JpaDsl.getGroup(request);
        return build(group, mapping);
    }

    public static QueryBuilder build(Group group, Map<String, String> mapping) {
        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        for (Filter filter : group.getFilters()) {
            String name = filter.field;
            if (mapping != null && mapping.containsKey(name)) {
                name = mapping.get(name);
            }
            Object value = group.getValue(filter);
            String operator = filter.operator.toUpperCase();
            QueryBuilder qb = createQueryBuilder(name, value, operator);
            join(group, builder, qb);

            if (group.getOperator().equalsIgnoreCase("or") && "name".equals(name)) {
                qb = createQueryBuilder("initials", value, "contains");
                join(group, builder, qb);
            }
        }

        for (Group grp : group.getGroups()) {
            QueryBuilder qb = build(grp, mapping);
            join(group, builder, qb);
        }
        return builder;
    }

    private static void join(Group group, BoolQueryBuilder builder, QueryBuilder qb) {
        if (qb == null) return;
        if (group.getOperator().equalsIgnoreCase("or")) {
            builder.should(qb);
        } else {
            builder.must(qb);
        }
    }

    private static QueryBuilder createQueryBuilder(String name, Object value, String operator) {
        QueryBuilder qb = null;
        switch (operator) {
            case "EQ":
                qb = QueryBuilders.termQuery(name, value);
                break;
            case "NE":
                QueryBuilder q = QueryBuilders.termQuery(name, value);
                qb = QueryBuilders.boolQuery().mustNot(q);
                break;
            case "LIKE":
                qb = QueryBuilders.matchPhraseQuery(name, value);
                break;
            case "GT":
                qb = QueryBuilders.rangeQuery(name).gt(value);
                break;
            case "LT":
                qb = QueryBuilders.rangeQuery(name).lt(value);
                break;
            case "GTE":
                qb = QueryBuilders.rangeQuery(name).gte(value);
                break;
            case "LTE":
                qb = QueryBuilders.rangeQuery(name).lte(value);
                break;
            case "wildcard":
                String query = String.format("*%s*", value).replaceAll("\\[", "").replaceAll("\\]", "");
                qb = QueryBuilders.wildcardQuery(name, query);
                break;
            case "match":
                qb = QueryBuilders.matchQuery(name, value);
                break;
            case "fuzzy":
                qb = QueryBuilders.fuzzyQuery(name, value);
                break;
            case "prefix":
                qb = QueryBuilders.prefixQuery(name, (String) value);
                break;
            case "contains":
                qb = QueryBuilders.regexpQuery(name, String.format( ".*%s.*" , value).replaceAll("\\[", "").replaceAll("\\]", ""));
                break;
        }
        return qb;
    }
}
